package cmd

import (
	"fmt"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"
)

var (
	rootCmd = &cobra.Command{
		Use:   "tcpgate",
		Short: "tcp test tool",
		Run:   tcp,
	}
)

func Execute() error {
	return rootCmd.Execute()
}

func init() {
	cobra.OnInitialize(initConfig)

	rootCmd.PersistentFlags().StringP("config", "c", "CONFIG FILE NAME", "absolute path to the config file")
	viper.BindPFlag("config", rootCmd.PersistentFlags().Lookup("config"))
	viper.SetDefault("config", "config.yaml")
}

func initConfig() {
	checkConfig()
	if err := viper.ReadInConfig(); err != nil {
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}
	fmt.Println("Using config file:", viper.GetString("config"))

	fs, ms := msgs()
	viper.Set("files", fs)
	viper.Set("messages", ms)
	fmt.Println("All config keys:", viper.AllKeys())
}

func checkConfig() {
	cfgFileName := viper.GetString("config")

	fi, err := os.Stat(cfgFileName)
	notExist := os.IsNotExist(err)
	if err != nil && !notExist {
		panic(fmt.Errorf("Can't open config file: %s \n", err))
	}

	if fi != nil && fi.IsDir() {
		panic(fmt.Errorf("[%s] is dir, but not config file: %s \n", cfgFileName, err))
	}

	if notExist {
		defaultConfig(cfgFileName)
	}

	viper.SetConfigFile(cfgFileName)
}

func defaultConfig(cfgFileName string) {
	cfg := struct {
		Addr    string
		Timeout time.Duration
	}{
		Addr:    "10.1.68.181:9000",
		Timeout: time.Minute,
	}

	cfgBytes, err := yaml.Marshal(cfg)
	if err != nil {
		panic(fmt.Errorf("Marshal default config: %s \n", err))
	}

	if err = ioutil.WriteFile(cfgFileName, cfgBytes, os.FileMode(0666)); err != nil {
		panic(fmt.Errorf("Write default config file: %s \n", err))
	}
}

func msgs() (fs, ms []string) {
	fis, err := ioutil.ReadDir(".")
	if err != nil {
		panic(fmt.Errorf("Search message file: %s \n", err))
	}

	for _, fi := range fis {
		fileName := fi.Name()
		if fi.IsDir() || filepath.Ext(fileName) != ".xml" {
			continue
		}

		fmt.Printf("Found a xml: %s \n", fileName)
		fb, err := ioutil.ReadFile(fileName)
		if err != nil {
			panic(fmt.Errorf("Open xml file: %s \n", err))
		}

		fs = append(fs, fileName)
		ms = append(ms, string(fb))
	}

	if len(ms) == 0 {
		fs, ms = crtExample()
	}

	for i := range ms {
		ms[i] = fmt.Sprintf("%010d%s", len(ms[i]), ms[i])
	}
	return
}

func crtExample() ([]string, []string) {
	exFile := "example.xml"
	msg := `<?xml version="1.0" encoding="UTF-8"?>
<service>
    <sys-header>
        <data name="SYS_HEAD">
            <struct>
                <data name="MODULE_ID">
                    <field type="string" length="2">CL</field>
                </data>
                <data name="USER_ID">
                    <field type="string" length="8">HJ100430</field>
                </data>
                <data name="TRAN_TIMESTAMP">
                    <field type="string" length="9">161153169</field>
                </data>
                <data name="SOURCE_BRANCH_NO">
                    <field type="string" length="2">HJ</field>
                </data>
                <data name="BRANCH_ID">
                    <field type="string" length="6">027008</field>
                </data>
                <data name="USER_LANG">
                    <field type="string" length="7">CHINESE</field>
                </data>
                <data name="SGM_CONTEXT">
                    <field type="string" length="53">1227534557174632448;1227534557287878657;false;ifp-uat</field>
                </data>
                <data name="TRAN_DATE">
                    <field type="string" length="8">20200213</field>
                </data>
                <data name="SEQ_NO">
                    <field type="string" length="27">HJS432020021316115317188888</field>
                </data>
                <data name="TRAN_MODE">
                    <field type="string" length="6">ONLINE</field>
                </data>
                <data name="SOURCE_TYPE">
                    <field type="string" length="2">HJ</field>
                </data>
                <data name="MESSAGE_TYPE">
                    <field type="string" length="2">27</field>
                </data>
                <data name="WS_ID">
                    <field type="string" length="3">006</field>
                </data>
                <data name="SERVER_ID">
                    <field type="string" length="9">127.0.0.1</field>
                </data>
                <data name="MESSAGE_CODE">
                    <field type="string" length="6">273004</field>
                </data>
                <data name="SERVICE_CODE">
                    <field type="string" length="7">SVR_FMS</field>
                </data>
                <data name="CONSUMER_ID">
                    <field type="string" length="3">HJS</field>
                </data>
            </struct>
        </data>
    </sys-header>
    <app-header>
        <data name="APP_HEAD">
            <struct>
                <data name="CURRENT_NUM">
                    <field type="string" length="1">0</field>
                </data>
                <data name="TOTAL_FLAG">
                    <field type="string" length="1">E</field>
                </data>
                <data name="PGUP_OR_PGDN">
                    <field type="string" length="1">1</field>
                </data>
                <data name="TOTAL_NUM">
                    <field type="string" length="2">-1</field>
                </data>
            </struct>
        </data>
    </app-header>
    <local-header>
        <data name="LOCAL_HEAD">
            <struct/>
        </data>
    </local-header>
    <body>
        <data name="CUST_NAME">
            <field type="string" length="3">董春玲</field>
        </data>
        <data name="DEPOSIT_ACCT">
            <field type="string" length="19">6236430901010030941</field>
        </data>
        <data name="DRAW_AMT">
            <field type="double" length="128">7000</field>
        </data>
        <data name="PROD_CODE">
            <field type="string" length="9">ZLC_GM_3Y</field>
        </data>
        <data name="ORDER_NO">
            <field type="string" length="16">RN202004170005TG</field>
        </data>
        <data name="ID_TYPE">
            <field type="string" length="1">0</field>
        </data>
        <data name="ID_CODE">
            <field type="string" length="18">230506198307110445</field>
        </data>
        <data name="BRAND_SERIES">
            <field type="string" length="5">SD001</field>
        </data>
        <data name="BANK_CUST_CODE">
            <field type="string" length="10">9000007842</field>
        </data>
        <data name="CHANNEL_NO">
            <field type="string" length="2">37</field>
        </data>
    </body>
</service>`

	err := ioutil.WriteFile(exFile, []byte(msg), os.FileMode(0666))
	if err != nil {
		panic(fmt.Errorf("Write example file: %s \n", err))
	}

	return []string{exFile}, []string{msg}
}
